
package todolist.personalization;

import java.util.ArrayList;
import java.util.ListIterator;

import todolist.entity.TaskEntity;

/**
 * Controls application behaviour related to Reminder Offset input and display.
 * Singleton class.
 * Iterator-styled for input descriptors, do not forget to rewind after each use.
 * Currently allows getting only, may allow reading/setting/writing in the future.
 * @author Ivan
 */
public class ReminderOffsetCustomizer {

	// handle singleton instance

	private static ReminderOffsetCustomizer _objROC;

	public static ReminderOffsetCustomizer getInstance() {
		if (_objROC == null)
			_objROC = new ReminderOffsetCustomizer();
		return _objROC;
	}
	
	// member attributes
	
	private ArrayList<NamesValuePair> _objInputOffsetList;
	private ArrayList<NameValuePair> _objDisplayOffsetList;
	private ListIterator<NamesValuePair> _objInputItr;
	private NamesValuePair _objInputCurrPair;
	
	private ReminderOffsetCustomizer() {
		String[] arrNone = {"nil", "null", "n.a.", "na", "none", "never"};
		String[] arrOnDueDT = {"due date", "duedate", "when due", "0minutes", "0mins", "00"};
		String[] arr1Min = {"1minutes", "1mins"};
		String[] arr5Min = {"5minutes", "5mins"};
		String[] arr15Min = {"15 minutes", "15 mins", "15minutes", "15mins"};
		String[] arr30Min = {"30 minutes", "30 mins", "30minutes", "30mins"};
		String[] arr1Hour = {"1hours", "1hrs"};
		String[] arr2Hour = {"2hours", "2hrs"};
		String[] arr3Hour = {"3hours", "3hrs"};
		String[] arr6Hour = {"6hours", "6hrs"};
		String[] arr12Hour = {"12 hours", "12 hrs", "12hours", "12hrs"};
		String[] arr1Day = {"1day", "1d"};
		_objInputOffsetList = new ArrayList<NamesValuePair>();
		_objInputOffsetList.add(new NamesValuePair(TaskEntity.NO_REMINDER_OFFSET, arrNone));
		_objInputOffsetList.add(new NamesValuePair(0, arrOnDueDT));
		_objInputOffsetList.add(new NamesValuePair(1, arr1Min));
		_objInputOffsetList.add(new NamesValuePair(5, arr5Min));
		_objInputOffsetList.add(new NamesValuePair(15, arr15Min));
		_objInputOffsetList.add(new NamesValuePair(30, arr30Min));
		_objInputOffsetList.add(new NamesValuePair(60, arr1Hour));
		_objInputOffsetList.add(new NamesValuePair(120, arr2Hour));
		_objInputOffsetList.add(new NamesValuePair(180, arr3Hour));
		_objInputOffsetList.add(new NamesValuePair(360, arr6Hour));
		_objInputOffsetList.add(new NamesValuePair(720, arr12Hour));
		_objInputOffsetList.add(new NamesValuePair(1440, arr1Day));
		_objInputItr = _objInputOffsetList.listIterator();
		_objInputCurrPair = null;
		_objDisplayOffsetList = new ArrayList<NameValuePair>();
		_objDisplayOffsetList.add(new NameValuePair(TaskEntity.NO_REMINDER_OFFSET, "None"));
		_objDisplayOffsetList.add(new NameValuePair(0, "Same as due date/time"));
		_objDisplayOffsetList.add(new NameValuePair(1, "1min earlier"));
		_objDisplayOffsetList.add(new NameValuePair(5, "5min earlier"));
		_objDisplayOffsetList.add(new NameValuePair(15, "15min earlier"));
		_objDisplayOffsetList.add(new NameValuePair(30, "30min earlier"));
		_objDisplayOffsetList.add(new NameValuePair(60, "1hr earlier"));
		_objDisplayOffsetList.add(new NameValuePair(120, "2hr earlier"));
		_objDisplayOffsetList.add(new NameValuePair(180, "3hr earlier"));
		_objDisplayOffsetList.add(new NameValuePair(360, "6hr earlier"));
		_objDisplayOffsetList.add(new NameValuePair(720, "12hr earlier"));
		_objDisplayOffsetList.add(new NameValuePair(1440, "1day earlier"));
	}
	
	/**
	 * Returns the default Reminder Offset when not specified.
	 */
	public int getDefaultReminderOffset() {
		return TaskEntity.NO_REMINDER_OFFSET; // negative offset implies none
	}
	
	// input Reminder Offset iteration methods

	/**
	 * Whether there is another input Descriptor. Do not forget to rewind first.
	 */
	public boolean hasNextInputReminderOffset() {
		return _objInputItr.hasNext();
	}

	/**
	 * Moves to the next input Descriptor.
	 */
	public void nextInputReminderOffset() {
		_objInputCurrPair = _objInputItr.next();
	}

	/**
	 * Resets input list so that call to hasNext/next will iterate from the start again.
	 */
	public void rewindInputReminderOffset() {
		_objInputItr = _objInputOffsetList.listIterator();
		_objInputCurrPair = null;
	}
	
	// input Reminder Offset getters

	/**
	 * Returns the value, in minutes, denoted by the current input Descriptors.
	 */
	public int getInputValue() {
		return _objInputCurrPair.getValue();
	}

	/**
	 * Returns the current possible input Descriptors.
	 */
	public String[] getInputDescriptors() {
		return _objInputCurrPair.getNames();
	}
	
	// display Reminder Offset facilitators

	/**
	 * Returns first found display Descriptor that matches value, or null if not found.
	 */
	public String findDisplayDescriptorByValue(int pintValue) {
		for (NameValuePair objPair : _objDisplayOffsetList)
			if (objPair.getValue() == pintValue)
				return objPair.getName();
		return null;
	}

	// private inner classes
	
	private class NamesValuePair {
		
		private int _intValue;
		private String[] _arrNames;
		
		private NamesValuePair(int pintValue, String[] parrNames) {
			_intValue = pintValue;
			_arrNames = parrNames;
		}
		
		private int getValue() {
			return _intValue;
		}
		
		private String[] getNames() {
			return _arrNames;
		}
		
		@Override
		public boolean equals(Object pobjOther) {
			if (pobjOther == null || !(pobjOther instanceof NamesValuePair))
				return false;
			NamesValuePair objOtherPair = (NamesValuePair) pobjOther;
			return _intValue == objOtherPair._intValue;
		}
		
	}
	
	private class NameValuePair {
		
		private int _intValue;
		private String _strName;
		
		private NameValuePair(int pintValue, String pstrName) {
			_intValue = pintValue;
			_strName = pstrName;
		}
		
		private int getValue() {
			return _intValue;
		}
		
		private String getName() {
			return _strName;
		}
		
		@Override
		public boolean equals(Object pobjOther) {
			if (pobjOther == null || !(pobjOther instanceof NameValuePair))
				return false;
			NameValuePair objOtherPair = (NameValuePair) pobjOther;
			return _intValue == objOtherPair._intValue;
		}
		
	}
	
}
